package npda;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author haoly
 * @title LexicalAnalyzer
 * @date 2025/4/22 11:44
 * @description TODO
 */
public class LexicalAnalyzer {

    private String input;

    public LexicalAnalyzer(String input) {
        this.input = input;
    }

    // 静态方法创建 GRAMMAR Map
    public static final List<GrammarRule> GRAMMAR = Arrays.asList(
            new GrammarRule("i", "if"),
            new GrammarRule("e", "else"),
            new GrammarRule("w", "while"),
            new GrammarRule("d", "do-nothing"),
            new GrammarRule("(", "\\("),
            new GrammarRule(")", "\\)"),
            new GrammarRule("{", "\\{"),
            new GrammarRule("}", "\\}"),
            new GrammarRule(";", ";"),
            new GrammarRule("=", "="),
            new GrammarRule("+", "\\+"),
            new GrammarRule("*", "\\*"),
            new GrammarRule("<", "\\<"),
            new GrammarRule("n", "[0-9]+"),
            new GrammarRule("b", "true|false"),
            new GrammarRule("v", "[a-z]+")
    );

    public List<String> analyze(){
        List<String> tokens = new ArrayList<>();
        while(moreTokens()){
            String nextToken = nextToken();
            if (nextToken == null) {
                System.err.println("Lexical error: No matching token found at beginning of remaining input " + this.input);
                break;
            }
            tokens.add(nextToken);
        }

        return tokens;

    }

    private String nextToken() {
        GrammarRule matchedRule = null;
        int maxLength = -1;
        Matcher matchedMatcher = null;
        for (GrammarRule rule : GRAMMAR) {
            Pattern pattern = rule.getPattern();
            Matcher matcher = pattern.matcher(this.input);
            if (matcher.lookingAt()) {
                int length = matcher.end();
                if (length > maxLength) {
                    maxLength = length;
                    matchedRule = rule;
                    matchedMatcher = matcher;
                }
            }
        }

        if (matchedRule == null) {
            return null;
        }
        this.input = stringAfter(matchedMatcher);
        return matchedRule.getToken();
    }

    private String stringAfter(Matcher matcher) {
        int endIndex = matcher.end();
        String remaining = this.input.substring(endIndex);
        remaining = remaining.replaceAll("^\\s+", "");
        return remaining;
    }

    public boolean moreTokens() {
        return this.input != null && !this.input.isEmpty();
    }

    public static class GrammarRule {
        private final String token;
        private final Pattern pattern;

        public GrammarRule(String token, String regex) {
            this.token = token;
            this.pattern = Pattern.compile(regex);
        }

        public String getToken() {
            return token;
        }

        public Pattern getPattern() {
            return pattern;
        }
    }
}
